package mud.player;

import java.io.EOFException;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.SwingUtilities;

import mud.Room;
import mud.Server;

/** Handles communication between the server and the telnet client */
public class CommandHandler implements Runnable {

    /** the logger */
    private static Logger log = Logger.getLogger(
        CommandHandler.class.getName());

    /** the mud server */
    private final Server server;

    /** the remote client terminal */
    private final Terminal terminal;

    /** the unit controlled via this console */
    private final PlayerUnit unit;

    /**
     * Constructor
     * @param server the mud server
     * @param terminal the remote client terminal
     */
    public CommandHandler(Server server, Terminal terminal) {
        this.server = server;
        this.terminal = terminal;
        this.unit = new PlayerUnit(terminal);
	}

	@Override
	public void run() {
        assert !SwingUtilities.isEventDispatchThread();

        try {
            handleLogin();
            for (;;) {
                handleCommand();
            }
        } catch (EOFException e) {
            log.finest("Received EOF from " + terminal);
        } catch (IOException e) {
            log.log(Level.SEVERE, "Network error from " + terminal, e);
        }

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                Room room = unit.getRoom();
                if (room != null) {
                    room.removeEntity(unit);
                }
                server.disconnect(terminal);
            }
        });
	}

    @Override
    public String toString() {
        assert SwingUtilities.isEventDispatchThread();
        return getClass().getSimpleName() + "["
            + "unit=" + unit + "]";
    }

    /**
     * Handles the client login process
     * @throws EOFException if the connection is closed 
     * @throws IOException if an I/O error occurs
     */
    private void handleLogin() throws EOFException, IOException {
        
        terminal.println("By what name shall your avatar be known?");
        
        final String input = terminal.readLine().trim();
        log.info("Received: \"" + input + "\" from " + terminal);

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                unit.setName(input);
                unit.enter(server.getWorld().getNewPlayerEntryPoint());
                unit.setRace(server.getWorld().getRaces().get(0)); // FIXME
                log.info("Login: " + unit);
            }
        });
    }

    /**
     * Parses an input string and executes the resulting command 
     * @throws EOFException if the connection is closed 
     * @throws IOException if an I/O error occurs
     */
    private void handleCommand() throws EOFException, IOException {
        
        final String input = terminal.readLine().trim();
        log.info("Received: \"" + input + "\" from " + terminal);

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                String[] inputs = input.split(" ", 2);
                String order = inputs[0];
                String args = "";
                if (inputs.length > 1) {
                    args = inputs[1];
                }
        
                Command command = Command.fromString(order);
                
                if (command != null) {
                    command.execute(unit, order, args);
                } else if (order.isEmpty()) {
                    // ignore
                } else {
                    terminal.println("Unknown command: \"" + order + "\"");  
                }
            }
        });
    }
}
